// @Author EthanScriptOn
// @Desc
package config_source_loader

import (
	"errors"
	"fmt"
	"gitee.com/fatzeng/srf_switch_config/config_context"
	"gitee.com/fatzeng/srf_switch_config/config_define"
	"gitee.com/fatzeng/srf_switch_config/config_node"
	"gitee.com/fatzeng/srf_switch_config/config_source_loader_management"
	"gitee.com/fatzeng/srf_switch_protocol/protocol/log"
)

type BasicSourceLoader struct {
	ConfigSourceLoaderSteps
	ctx *config_context.ConfigInitializationContext
}

func GenerateBasicSourceLoader(steps ConfigSourceLoaderSteps) (*BasicSourceLoader, error) {
	if steps == nil {
		return nil, errors.New("steps can not be nil")
	}
	basicSourceLoader := new(BasicSourceLoader)
	basicSourceLoader.ConfigSourceLoaderSteps = steps
	return basicSourceLoader, nil
}

func (b *BasicSourceLoader) TagLoading(filePath string) {
	b.ctx.GetFileLoadingCache()[filePath] = struct{}{}
}

func (b *BasicSourceLoader) CanSupport(configSourceType config_define.ConfigSourceType) (err error) {
	getSupportedList, err := config_source_loader_management.GetSupportedList()
	if err != nil {
		return err
	}
	if _, ok := getSupportedList[configSourceType]; !ok {
		return fmt.Errorf("the fileType [%+v] is not supported", configSourceType)
	}
	return
}

func (b *BasicSourceLoader) SetUpResources(source interface{}) (err error) {
	if source == nil {
		return errors.New("cannot set empty resources")
	}
	ctx, ok := source.(*config_context.ConfigInitializationContext)
	if !ok {
		return errors.New("the source type is not supported need *config_config_context.ConfigInitializationContext")
	}
	b.ctx = ctx
	return
}

func (b *BasicSourceLoader) GetConfigSourceType() config_define.ConfigSourceType {
	panic(errors.New("this function needs to be rewritten"))
}

func (b *BasicSourceLoader) ReadContent() ([]string, error) {
	panic(errors.New("this function needs to be rewritten"))
}
func (b *BasicSourceLoader) Initialization() (err error) {
	log.Logger().Info("You can implement this function to perform some preprocessing operations")
	return
}

func (b *BasicSourceLoader) LoadConfigSource() (interface{}, error) {
	panic(errors.New("this function needs to be rewritten"))
}

func (b *BasicSourceLoader) ShouldExecute(interface{}) (bool, error) {
	panic(errors.New("this function needs to be rewritten"))
}

func (b *BasicSourceLoader) SetSource(source interface{}) (err error) {
	return b.SetUpResources(source)
}

func (b *BasicSourceLoader) LoadSourceLoaderNodes(lines []string) ([]*config_node.SourceLoaderNode, error) {
	describes, err := b.ConfigSourceLoaderSteps.ConvertLineDescribe(lines)
	if err != nil {
		return nil, err
	}
	return b.ConvertSourceLoaderNode(describes)
}

func (b *BasicSourceLoader) ConvertSourceLoaderNode(describes []*SegmentLineDescribe) ([]*config_node.SourceLoaderNode, error) {
	segments, err := b.ConfigSourceLoaderSteps.SplitSegment(describes)
	if err != nil {
		return nil, err
	}
	sourceLoaderNodes := make([]*config_node.SourceLoaderNode, 0)
	for _, segment := range segments {
		sourceLoaderNode, err := b.BuildSourceLoaderNode(segment)
		if err != nil {
			return nil, err
		}
		sourceLoaderNodes = append(sourceLoaderNodes, sourceLoaderNode)
	}
	return sourceLoaderNodes, nil
}

func (b *BasicSourceLoader) BuildSourceLoaderNode(segment Segment) (*config_node.SourceLoaderNode, error) {
	sourceLoaderNode := config_node.GenerateSourceLoaderNode()
	sourceLoaderNode.SetContent(segment)
	for _, describePtr := range segment {
		describe := describePtr
		for _, keyDescribe := range describe.multiKeySlice {
			if keyDescribe.level == 0 {
				sourceLoaderNode.SetSegmentHead(config_define.NodeElemType(keyDescribe.key))
				continue
			}
			sourceLoaderNode.AppendSegmentSons(config_define.NodeElemType(keyDescribe.key))
		}
	}
	return sourceLoaderNode, nil
}

func (b *BasicSourceLoader) PerfectSourceLoaderResultWithSegmentInformation(sourceLoaderResult *SourceLoaderResult, sourceLoaderNodes []*config_node.SourceLoaderNode) error {
	for _, sourceLoaderNodePtr := range sourceLoaderNodes {
		sourceLoaderNode := sourceLoaderNodePtr
		segmentInformation, err := b.ObtainConstructionInformation(sourceLoaderNode)
		if err != nil {
			return err
		}
		sourceLoaderResult.AppendSegmentsInformation(segmentInformation)
	}
	return nil
}

func (b *BasicSourceLoader) ObtainConstructionInformation(sourceLoaderNode *config_node.SourceLoaderNode) (*SegmentInformation, error) {
	sourceLoaderNodeMap, err := b.ConfigSourceLoaderSteps.ConvertSegmentToMap(sourceLoaderNode)
	if err != nil {
		return nil, err
	}
	segmentInformation, err := b.BuildSegment(sourceLoaderNode, sourceLoaderNodeMap)
	if err != nil {
		return nil, err
	}
	return segmentInformation, nil
}

func (b *BasicSourceLoader) BuildSegment(sourceLoaderNode *config_node.SourceLoaderNode, segmentLoaderResult map[string]interface{}) (*SegmentInformation, error) {
	segmentInformation := new(SegmentInformation)
	segmentInformation.SetSegmentOriginalNode(sourceLoaderNode)
	segmentInformation.SetSegmentLoaderResult(segmentLoaderResult)
	return segmentInformation, nil
}
